package org.folio.rest.impl.other.reserve_station;


import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import io.vertx.core.Vertx;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import org.folio.cql2pgjson.exception.FieldException;
import org.folio.rest.impl.other.PartyUtil;
import org.folio.rest.impl.other.reserve_station.model.ReserveDelayed;
import org.folio.rest.impl.other.take.TakeInterface;
import org.folio.rest.jaxrs.model.Party;
import org.folio.rest.persist.PostgresClient;
import org.folio.rest.persist.cql.CQLWrapper;

import java.util.Date;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/****
 * 活动报名处理器
 * 主要负责日常活动的扫描
 * 扫描将在当天开始报名的活动,然后转交到带开始的队列中
 */
public class ReserveStation implements TakeInterface {
    private final static Logger logger = LoggerFactory.getLogger("modparty");
    private static String tenant;
    private static Vertx vertx;
    private ReserveStartPond reserveStartPond;
    private ReserveEndPond reserveEndPond;
    private ThreadPoolExecutor threadPoolWait = new ThreadPoolExecutor(
            1, 1, 10, TimeUnit.SECONDS,
            new ArrayBlockingQueue<Runnable>(1),
            new ThreadPoolExecutor.DiscardOldestPolicy());
    private ThreadPoolExecutor threadPoolAlready = new ThreadPoolExecutor(
            1, 1, 10, TimeUnit.SECONDS,
            new ArrayBlockingQueue<Runnable>(1),
            new ThreadPoolExecutor.DiscardOldestPolicy());
    private static ConcurrentHashMap<String, Party> partyMap =
            new ConcurrentHashMap<>();


    public ReserveStation(Vertx vertx, String tenant) {
        this.vertx = vertx;
        ReserveStation.tenant = tenant;
        init();
    }
    @Override
    public   Party getPartyById(String partyId) {
        return partyMap.get(partyId);
    }

    public void init() {

        this.reserveStartPond = new ReserveStartPond();
        this.reserveEndPond = new ReserveEndPond(vertx, tenant);
        this.reserveStartPond.addReserveEndPond(this.reserveEndPond);
        this.reserveStartPond.addReserveStation(this);
        threadPoolWait.execute(this.reserveStartPond);
        threadPoolAlready.execute(this.reserveEndPond);


        searchParty(tenant, vertx);

    }

    @Override
    public ReserveEndPond getReserveEndPond() {
        return this.reserveEndPond;
    }

    @Override
    public void timeTake() {
        searchParty(tenant, vertx);
        this.reserveStartPond.clearOutDate();
        this.reserveEndPond.clearOutDate();
    }

    private static void searchParty(String tenant, Vertx vertx) {
        Date date = new Date();
        String dayStart = DateUtil.formatDateTime(DateUtil.beginOfDay(date));
        String dayEnd = DateUtil.formatDateTime(DateUtil.endOfDay(date));
        String query = "( isDel = 0 and ( reserveStartDate >= " + dayStart + " and reserveStartDate <= " + dayEnd + ") or ( reserveEndDate >= " + dayStart + " and reserveEndDate <= " + dayEnd + ") and category <> 3 and state <> 1 and approval == 1 and isCalendar = 0  )";
        CQLWrapper cql = null;
        try {
            cql = PartyUtil.getCQL(query, -1, -1, "party");
        } catch (FieldException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        PostgresClient.getInstance(vertx, tenant).get("party", Party.class, new String[]{"*"}, cql,
                true, false, reply -> {
                    if (reply.succeeded()) {
                        List<Party> list = reply.result().getResults();
                        logger.info("共有：" + list.size() + "条活动，今天可以报名！");
                        list.forEach(action -> {
                            // setJob(action, tenant, vertx);
                            ReserveDelayed reserveDelayed = createPartyReserveDelay(action, tenant);
                            ReserveStartPond.add(reserveDelayed);
                            partyMap.put(reserveDelayed.getPartyId(), action);
                        });
                    }
       });
    }


    private static ReserveDelayed createPartyReserveDelay(Party partyGroup, String tenantId) {
        ReserveDelayed reserveDelayed = new ReserveDelayed();
        reserveDelayed.setExpTime(DateUtil.parseDateTime(partyGroup.getReserveStartDate()).getTime());
        reserveDelayed.setEndTime(partyGroup.getReserveEndDate());
        reserveDelayed.setReserveAmount(partyGroup.getQuota());
        reserveDelayed.setPartyId(partyGroup.getId());
        reserveDelayed.setTenantId(tenantId);
        return reserveDelayed;
    }
    @Override
    public   void removeAndFreed(final Party partyGroup) {
        ReserveStartPond.remove(partyGroup.getId());
        ReserveEndPond.remove(partyGroup.getId());
        partyMap.remove(partyGroup.getId());
    }

    public void clearPartyById(final String partyId) {
        partyMap.remove(partyId);
    }

    @Override
    public void update() {
        timeTake();
    }

    @Override
    public void setJob(Party partyGroup) {
        if (ObjectUtil.isEmpty(partyGroup)) {
            logger.info(" add job err , partyGroup is null ");
            return;
        }
        if (ObjectUtil.isEmpty(vertx)) {
            logger.info(" add job err , vertx is null ");
            return;
        }
        if (StrUtil.isNullOrUndefined(tenant )) {
            logger.info(" add job err , tenantId is null ");
            return;
        }
        if (StrUtil.isNullOrUndefined(partyGroup.getReserveStartDate())) {
            logger.info(" add job err , ReserveStartDate is null ");
            return;
        }
        Date date = new Date();
        DateTime dateEnd = DateUtil.parseDateTime(partyGroup.getReserveEndDate());
        if (DateUtil.isIn(DateUtil.parse(partyGroup.getReserveStartDate()),
                DateUtil.beginOfDay(date), DateUtil.endOfDay(date))
                && "1".equals(partyGroup.getApproval().toString())
                && date.before(dateEnd) && !partyGroup.getCategory().toString().equals("3")) {
            ReserveDelayed reserveDelayed = createPartyReserveDelay(partyGroup, tenant);
            ReserveStartPond.add(reserveDelayed);
            partyMap.put(reserveDelayed.getPartyId(), partyGroup);
            logger.info("add queue job success, party name is 【 " + partyGroup.getPartyName() + "】");
        } else {
            logger.info(" add job err , partyAttendDate is not today end ");
            return;
        }
    }
}
